perm filename NOTES.C[1,RWF] blob
sn#548612 filedate 1980-12-05 generic text, type C, neo UTF8
COMMENT ā VALID 00019 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00004 00002 This is file FLOYD.C[1,PHY] at the Stanford AI Lab (SU-AI), last written
C00006 00003 PROCEDURE NAME(...) BEGIN
C00008 00004
C00010 00005 APPENDIX J. FILE SPECIFICATIONS [D4].
C00013 00006 HOW TO TALK ABOUT SETS OF FILES:
C00017 00007 APPENDIX K. COMMON PROGRAMMING ERRORS.
C00023 00008 (21) Conditional expressions without alternative: A := IF B THEN C+D .
C00024 00009 Examples follow, showing typical error messages resulting from common SAIL
C00026 00010 We shall show the effects of making changes that leave the program
C00029 00011 The first error causes multiple error messages, all at places where COL is
C00033 00012 BLOCK FOUND WHILE FLUSHING STATEMENT - WILL TRY TO PARSE IT.
C00036 00013 The second message correctly diagnosed the problem. The compiler soon got
C00039 00014 APPENDIX M. POLYNOMIAL MULTIPLICATION.
C00045 00015 BEGIN "MAIN"
C00047 00016 [Into SAIL notes, insert before CONVERSION OF STRINGS TO NUMBERS.]
C00049 00017 (4) To remove initial, final, and multiple spaces from a string S :
C00051 00018 RANDOM NUMBERS.
C00063 00019 For a normally distributed number (this distribution is the bell-shaped
C00067 ENDMK
Cā;
This is file FLOYD.C[1,PHY] at the Stanford AI Lab (SU-AI), last written
July 31, 1978. Bob Floyd (aka RWF at SAIL, R.RWF at LOTS) wrote it, maintains
it, and welcomes suggestions.
APPENDIX I. A DISCIPLINE OF PUNCTUATION AND INDENTATION FOR SAIL COMMANDS.
If you have trouble remembering where the semicolons go, use this method, which
uses more blocks than are absolutely necessary, but which is easy to read and
to write correctly.
All primitive commands are written with a semicolon at the end of the line.
All composite commands are written in one of these forms:
FOR ... DO BEGIN
C1
C2
.
.
.
Cn
END;
WHILE ... DO BEGIN
C1
C2
.
.
.
Cn
END;
IF ... THEN BEGIN
C1
C2
.
.
.
Cn
END;
IF ... THEN BEGIN
C1
C2
.
.
.
Cn
END ELSE BEGIN
Cn+1
Cn+2
.
.
.
Cm
END;
PROCEDURE NAME(...); BEGIN
C1
C2
.
.
.
Cn
END;
CASE ... OF BEGIN
[1] C1
[2] C2
[3] C3
.
.
.
[n] Cn (it is essential not to end this line
END; with a semicolon)
DO BEGIN
C1
C2
.
.
.
Cn
END UNTIL E;
Under this discipline all commands (except the last in a CASE statement)
end with a semicolon, which you can think of as part of the command. The
command to do nothing is just the semicolon by itself. All the component
commands of a composite command are indented more than the first and last
lines; by looking straight down from the first line, you find the matching
last line, starting with END.
Comments are written before the command at the same level of indentation as
its first line. Every line ends with either a semicolon, or the word BEGIN.
The system is flexible; when additions or deletions are made, you don't have
to change other lines.
APPENDIX J. FILE SPECIFICATIONS [D4].
The full specification of any file belonging to you is of the form
filename.filetype.generation
Use up to six letters and digits for the filename, chosen to help you
remember what the file is about. Use standard filetypes such as SAI,
according to the rules in File Types, below. The generation number will be
suppled automatically.
To refer to a file in someone else's directory [D4.3.1] , precede the
filename with his user name or directory name in angular brackets:
<s.smith>hisfilename.filetype.gen
You will find useful files in the directory <C.CS10X>
There are other kinds of file names with special meanings [D4.2].
File Types [D4.5]
SAI: a SAIL program
OUT: the output program from a program
DAT: input data for a program
TXT: text in English (or other human language)
TMP: a file which you want deleted when you log out
HDR: a header file for incorporation into programs
REL or BIN: a file in machine language
KNT: a file of execution counts, used by PROFIL
LST: a listing file, to be deleted after printing [D8.1.4]
DOC: documentation
CRF: a cross reference file [D8.2.4]
CMD: a file of TOPS-20 commands to happen automatically when you log in
[D3.2.4, D3.2.5]
CTL: a control file for a batch job [D3.4]
LOG: a log file for a batch job [D3.4]
EXE: an executable file in machine language [D8.1.5]
INI: a file of standard options to be used with EDIT, PRINT, and SUBMIT
[D7.4]
FOR: FORTRAN program
Files you create will usually be of types SAI, OUT, DAT, TXT, REL, or HDR.
HOW TO TALK ABOUT SETS OF FILES:
If you want to delete, print, list, see directory information about, etc.,
several files at once, you can name a subset of your files as follows. The
asterisk, * , stands for any file name, so @%PRINT$ *.SAI% will print
all your SAIL files. It also stands for any file type, so
@%DIRectory$ MYPROG.*.2%
will give you directory information about both MYPROG.SAI.2 and
MYPROG.OUT.2 . See [D4.8].
In most places where you would want to, you can give the names of a set of
files, separated by commas [D4.11], like
@%PRINT$ MYPROG.SAI, RESULTS.OUT%
Giving a file name alone is like following it with .* [D4.5].
If you don't mention a generation number, the system provides one as follows:
When you create a file, the generation number used is one more than the
highest existing generation of that file. When you read a file (editing,
compiling, printing etc.) the highest generation is used. When you delete
or undelete, all generations are used.
SOME USEFUL THINGS THAT CONTROL CHARACTERS DO (References are to DEC SYSTEM 20
OVERVIEW):
C (Twice) calls TOPS-20.
I Is the tab key.
O Stops, or restarts, output to the terminal, without stopping the
program that is running.
Q Looks at the next page of a multi-page terminal display.
S Stops the terminal display from moving, until Q restrarts it.
[D9.3.1]
T Gives load and usage statistics. [D7.6.3]
U Cancels current line (then hit RETURN).
W Deletes last word typed.
Z Signs off when entering data from terminal. In particular, used to
end a message you are mailing.
ESC Asks TOPS-20 to fill out the rest of a word for you if it can, and
prompt for the next word.
RUBOUT Deletes last character typed (so does BACKSPACE).
REPEAT While held down, makes other keys repeeeeeeeeeat.
SPACE Ends TOPS-20 operands.
? Asks for a list of available choices you can type next.
! Makes rest of the line a comment, ignored by TOPS-20.
APPENDIX K. COMMON PROGRAMMING ERRORS.
(1) Failure to have the same number of BEGINs and ENDs. With too many
ENDs there may be no error message. With too few, the likely message
is FATAL END OF SOURCE FILE at the end of the program. Omission of
BEGINs and ENDs is also likely to give rise to UNDECLARED IDENTIFIER
messages. To control this problm, it is advisable to label BEGINs
and ENDs, at least for the blocks of substantial size (about ten
lines).
(2) Omission of the semicolon. Symptoms: INSERTING FORGOTTEN SEMICOLON
or SYNTAX ERROR.
(3) Putting some of the commands of a block before some of the
declarations:
BEGIN
INTEGER N;
N := READ;
REAL ARRAY A[1:N];
.
.
.
END
(4) Omission of semicolon after comments. Symptom: usually loss of the
following command, often with no error message.
(5) Including spaces in combinations like := , <= , SOURCE!FILE ,
SETFORMAT .
(6) Omitting closing quote marks. Symptoms: many.
Example: PRINT("X =,X,"Y =",Y);
(7) Typing more than 80 characters per line. (This goes to a new line on
the terminal, but continues on the same line on paper listings of the
program, eventually spilling some of the program off the right edge of
the paper.)
(8) Forgetting to provide for spacing in output. Trying to print more
than 132 characters per line, and more than 60 lines per page.
(9) Running constants and identifiers together: PRINT(10000DIV X) .
(10) Omitting multiply signs: PRINT((A+B)(C-D),B**2-4AC) .
Symptom: UNDECLARED VARIABLE.
(11) Using unary minus after an operator without parenthesizing: A**-B .
(12) Failure to initialize variables used in an iteration. Failure to
initialize them often enough (at the right level of iteration).
(13) Using an integer variable to hold a quantity which may logically be
a non-integer:
INTEGER C;
C := SQRT(A**2 + B**2);
(14) Failure to prompt for input; to check it for validity; to reread
if invalid data are found; to echo all input in the output listing.
(15) Including semicolon just before ELSE.
(16) IF ... THEN C ELSE C ELSE C . Symptom: SYNTAX ERROR.
1 2 3
(17) Using = for := :
FOR I = 1 STEP 1 UNTIL 10 DO
A[I] = 3*I-1;
(18) Using := for = :
IF A := B THEN PRINT("YES") ELSE PRINT("NO")
(19) Patterns like WHILE X > Y THEN X := X-1 , IF P = Q DO PRINT(R) ,
REPEAT X := X-1 WHILE X > Y .
(20) Forgetting that many operations, such as MOD and DIV, assign their
arguments to integer variables before doing their work.
(21) Conditional expressions without alternative: A := IF B THEN C+D .
(22) Forgetting that, as data, upper and lower case letters are not
considered equal. Example:
PRINT("DO YOU WANT ...");
S := READLINE
IF EQU(S,"YES") THEN ... ELSE ...
Examples follow, showing typical error messages resulting from common SAIL
syntax errors.
The following is a correct SAIL program:
@TYPE (FILE) ROOK.SAI.3
00100 COMMENT ROOK ON CHESSBOARD;
00200 BEGIN "MAIN"
00300 REQUIRE "<C.CS10X>INTRO.HDR" SOURCE!FILE;
00400 INTEGER ROOKRO, ROOKCOL, ROW, COL;
00500
00600 ROOKROW := READ;
00700
00800 WHILE ROOKROW < 1 OR ROOKROW > 8 DO BEGIN
00900 PRINT("TRY AGAIN");
01000 ROOKROW := READ;
01100 END;
01200
01300 PRINT("ROW =", ROOKROW);
01400 ROOKCOL := READ;
01500
01600 WHILE ROOKCOL < 1 OR ROOKCOL > 8 DO BEGIN
01700 PRINT("TRY AGAIN");
01800 ROOKCOL := READ;
01900 END;
02000
02100 PRINT("COLUMN =", ROOKCOL, NEWLINE);
02200 COMMENT NOW PRINT BOARD;
02300
02400 FOR ROW UPTO 8 DO BEGIN "ROW"
02500 FOR COL UPTO 8 DO BEGIN "COL"
02600 IF ROW = ROOKROW THEN BEGIN "ONROW"
02700 IF COL = ROOKCOL THEN BEGIN
02800 PRINT("R");
02900 END ELSE BEGIN
03000 PRINT("*");
03100 END
03200 END "ONROW" ELSE BEGIN "OFFROW"
03300 IF COL = ROOKCOL THEN BEGIN
03400 PRINT("*");
03500 END ELSE BEGIN
03600 PRINT(".");
03700 END;
03800 END "OFFROW";
03900 END "COL";
04000 END "ROW";
04100
04200 END "MAIN";
We shall show the effects of making changes that leave the program
grammatically incorrect.
(1) Omitting an END, by deleting line 1100. When we execute the
program, we see the following on the terminal.
@EXECUTE (FROM) ROOK.SAI
ROOK.SAI.4 1
<C.CS10X>INTRO.HDR.1 1
<SAIL>IOSAIL.HDR.21 1
Fatal end of source file, scanning file.
BEGIN MAIN 00200/1
Last source-file macro: UPTO 02500/1
Current macro: UPTO
ROOK.SAI.4, PAGE 1
04100
The first line after the EXECUTE is the file ROOK.SAI.4 which was compiled,
followed by a 1 to show that the compiler was on page 1 of that file. The
next line shows that the introductory header was incorporated (by the
REQUIRE line). The third shows that the IOSAIL package in turn was REQUIREd
by INTRO. The fourth line is the error message; the compiler came to the end
of the ROOK.SAI file without having seen a complete program. The next line
shows that the incomplete structure was the BEGIN, labeled MAIN, on line
200 of page 1 (the only page) of the program. The next two lines are
irrelevant to this error. They refer to the fact that line 2500 uses UPTO
as an abbreviation for := 1 STEP 1 UNTIL .
(2) Failing to declare the variable COL ,
00400 INTEGER ROOKROW, ROOKCOL, ROW;
and omitting a semicolon
01700 PRINT("TRY AGAIN")
causes these error messages.
INSERTING FORGOTTEN SEMI-COLON.
ROOK.SAI.5, PAGE 1
01800 ROOKCOL
:= READ;
UNDECLARED IDENTIFIER: COL
ROOK.SAI.5, PAGE 1
02500 FOR COL
UPTO 8 DO BEGIN "COL"
IMPOSSIBLE TYPE COERCION
ROOK.SAI.5, PAGE 1
02700 IF COL = ROOKCOL THEN
BEGIN
IMPOSSIBLE TYPE COERCION
ROOK.SAI.5, PAGE 1
03300 IF COL = ROOKCOL THEN
BEGIN
End of compilation.
The first error causes multiple error messages, all at places where COL is
used. Notice that the errors were not discovered until the compiler had gone
a few symbols past COL in each case. The missing semicolon was automatically
restored; this is not always possible. The line 1800 is broken, continuing
on a lower line in the error message, after ROOKCOL ; that is where the
compiler was working when it found the error. Often, as in this case, the
actual error was on an earlier line.
(3) Inserting a space into a symbol
01400 ROOKCOL : = READ
(should be := ) and inserting a semicolon before ELSE
02900 END; ELSE BEGIN
causes these error messages:
SYNTAX ERROR. CURRENT STATEMENT OR DECLARATION WILL BE FLUSHED.
ROOK.SAI.6, PAGE 1
01400 ROOKCOL :
= READ;
STATEMENT FLUSHED.
EXTRANEOUS "ELSE", WILL BE IGNORED
ROOK.SA.6, PAGE 1
02900 END ; ELSE
BEGIN
End of compilation.
The first error was not diagnosed in detail. SYNTAX ERROR is a catchall
phrase for numerous grammatical problems. The error was discovered when the
compiler was looking at
ROOKCOL :
,however, which brings the reader's attention to the source of the problem.
The second error was diagnosed as resulting from an extra ELSE, rather than
an extra semicolon. As this indicates, you should not assume that error
messages tell you how to fix your program. They merely provide evidence
about what the compiler couldn't interpret.
(4) Leaving out an essential space
00800 WHILE ROOKROW < 1 OR ROOKROW > 8DO BEGIN
and using WHILE ... THEN instead of WHILE ... DO
01600 WHILE ROOKCOL < 1 OR ROOKCOL > 8 THEN BEGIN
causes these error messages:
ILLEGAL REAL CONSTANT
ROOK.SAI.7, PAGE 1
00800 WHILE ROOKROW < 1 OR ROOKROW > 8D
O BEGIN
ILLEGAL CONSTANT
ROOK.SAI.7, PAGE 1
00800 WHILE ROOKROW < 1 OR ROOKROW > 8D
O BEGIN
SYNTAX ERROR AT END OF EXPRESSION - WILL CHECK FOR PARENTHESES MISMATCH
ROOK.SAI.7, PAGE 1
00800 WHILE ROOKROW < 1 OR ROOKROW > 8DO
BEGIN
BLOCK FOUND WHILE FLUSHING STATEMENT - WILL TRY TO PARSE IT.
BLOCK END OKAY - FLUSH OF STATEMENT CONTINUES.
STATEMENT FLUSHED.
SYNTAX ERROR AT END OF EXPRESSION - WILL CHECK FOR PARENTHESES MISMATCH
ROOK.SAI.7, PAGE 1
01600 WHILE ROOKCOL < 1 OR ROOKCOL > 8 THEN
BEGIN
BLOCK FOUND WHILE FLUSHING STATEMENT - WILL TRY TO PARSE IT.
BLOCK END OKAY - FLUSH OF STATEMENT CONTINUES.
STATEMENT FLUSHED.
End of compilation.
The first shows that the compiler began to interpret 8 as a numerical
constant, then found the D in it and was confused. The same confusion
caused the next three error messages. You will often find that correcting
the first error in a program will make many error messages go away. The
last two error messages reflect the second error.
(5) Putting a declaration after a command, by putting line 400
(now line 650) after line 600.
00600 ROOKROW := READ;
00650 INTEGER ROOKROW, ROOKCOL, ROW, COL;
resulted in these error messages:
UNDECLARED IDENTIFIER: ROOKROW
ROOK.SAI.9, PAGE 1
00600 ROOKROW
:= READ;
CANNOT BEGIN A DECL OR STMNT LIKE THIS.
(MOST LIKELY A DECL AFTER A STMNT)
ROOK.SAI.9, PAGE 1
00650 INTEGER
ROOKROW, ROOKCOL, ROW, COL;
STATEMENT FLUSHED.
IMPOSSIBLE TYPE COERCION
ROOK.SAI.9, PAGE 1
00300 WHILE ROOKROW < 1 OR
ROOKROW, ROOKCOL, ROW, COL;
IMPOSSIBLE TYPE COERCION
ROOK.SAI.9, PAGE 1
00300 WHILE ROOKROW < 1 OR ROOKROW > 8 DO
BEGIN
Can't PRINT this syntactic type
ROOK.SAI.9, PAGE 1
01300 PRINT("ROW =", ROOKROW)
;
DRYROT -- GETAD
ROOK.SAI.9, PAGE 1
01300 PRINT("ROW =", ROOKROW)
;
The second message correctly diagnosed the problem. The compiler soon got
too confused to continue; this is what DRYROT means.
(6) Using = instead of := as the assignment operator
01800 ROOKCOL = READ;
and omitting a closing quote
02100 PRINT("COLUMN =, ROOKCOL, NEWLINE);
resulted in these errors:
SYNTAX ERROR. CURRENT STATEMENT OR DECLARATION WILL BE FLUSHED.
ROOK.SAI.11, PAGE 1
01800 ROOKCOL =
READ;
STATEMENT FLUSHED.
SYNTAX.ERROR. CURRENT STATEMENT OR DECLARATION WILL BE FLUSHED.
ROOK.SAI.11, PAGE 1
02400 FOR ROW UPTO 8 DO BEGIN "ROW
"
Fatal end of source file, scanning file.
BEGIN MAIN 00200/1
Last source-file macro: CLOSEALL 01400/1
Current macro: THRU
ROOK.SAI.11, PAGE 1
04200
The first message clearly reflects the first error. The compiler thought that
the quoted string in line 02100 went on up to the first quote in line 02400,
where it was immdiately followed by ROW, as if one had written
PRINT("XYZ" ROW... .
From here on, most of the program (except for block labels) was thoght to be
long quoted strings, so the ENDs were missed. At the end of the file,
therefore, there were still incomplete blocks. Omitting quote marks causes
very confusing error messages; check that every line includes an even number
of quote marks.
APPENDIX M. POLYNOMIAL MULTIPLICATION.
Let A[0] + A[1]X + A[2]X**2 + ... + A[DA]X**DA and B[0] + B[1]X + ...
+ B[DB]X**DB be two polynomials. To get the coefficients of the product
polynomial, form the product of every monomial A[I]X**I from A , with
every monomial B[J]X**J from B . This contributes a term A[I]B[J]X**(I+J)
to the product, C , increasing C[I+J] by A[I]B[J] :
FOR K := 0 STEP 1 UNTIL DA + DB DO
C[K] := 0;
FOR I := 0 STEP 1 UNTIL DA DO
FOR J := 0 STEP 1 UNTIL DB DO
C[I+J] := C[I+J] + A[I] * B[J]
FOR K := 0 STEP 1 UNTIL DA + DB DO
PRINT(C[K],NEWLINE)
This organization of the nested iteration is much easier than trying to
compute each coefficient of C completely before going on to the next.
If you try to do so, you find that the program must consist of about
three separate nested iterations.
Suppose you want to raise a polynomial A to a power -- perhaps the fifth.
Schematically, one way to do it is:
Put A*A in B
Put A*B in C (i.e., A**3)
Put A*C in D (i.e., A**4)
Put A*D in E (i.e., A**5)
This entails writing out the nested loops for the multiplication four times.
It is much simpler to use another level of iteration: Start B off as the
polynomial 1 , and let the outer iteration successively change its value
to A , A**2 , A**3 , A**4 , A**5 . This is done, schematically, by:
Put 1 in B ;
FOR I := 1 STEP 1 UNTIL 5 DO
BEGIN
COMMENT ASSUME B IS A**(I-1)
Put A*B in C ;
Put C in B
COMMENT NOW B IS A**I
END
Writing the program out in detail,
BEGIN "MAIN"
REAL ARRAY A[0:10], B, C[0:50];
INTEGER DA, DB, DC, POWER;
COMMENT INPUT POLYNOMIAL A;
DA := READ;
FOR I := 0 STEP 1 UNTIL DA DO
A[I] := READ;
COMMENT PUT 1 IN B;
DB := 0;
B[0] := 1;
FOR POWER := 0 STEP 1 UNTIL 4 DO
BEGIN "POW"
DB := POWER * DA;
DC := DA + DB;
FOR K := 0 STEP 1 UNTIL DC DO C[K] := 0;
FOR I := 0 STEP 1 UNTIL DA DO
FOR J:= 0 STEP 1 UNTIL DB DO
C[I+J] := C[I+J] + A[I] * B[J];
COMMENT AB IS IN C;
FOR K := 0 STEP 1 UNTIL DC DO
B[K] := C[K]
END "POW"
END "MAIN"
The key to the above program is leaving the result of each iteration
(originally in array C ) in the place (array B ) where the input is
expected for the next iteration. Generally, if you want to iterate a
series of computations, you must match up its output with its own input.
[Into SAIL notes, insert before CONVERSION OF STRINGS TO NUMBERS.]
EXAMPLES OF STRING MANIPULATION IN SAIL.
In the following procedure bodies, it is assumed that the input is in string
variable S , and that string variable T and integer (or string) variable C
are available for use, along with integer variable L .
(1) To change the letters in a string to upper case:
BEGIN
INTEGER D;
T := NULL;
D := "A"-"a";
WHILE S NEQ NULL DO
BEGIN "MOVE"
C := LOP(S);
IF "a" <= C <= "z" THEN C := C+D;
T := T & C
END "MOVE"
END
(2) To change every occurrence of string X in S to a string Y :
BEGIN
T := NULL;
L := LENGTH(X);
WHILE LENGTH(S) >= L DO
BEGIN "MOVE"
IF EQU(S[1 FOR L],X) THEN
BEGIN
T := T & Y;
S := S[L+1 TO INF]
END
ELSE T := T & LOP(S)
END "MOVE"
RETURN(T & S)
END
(3) To test whether S is alphabetically earlier than T (returning
TRUE also if they are equal, and assuming that letters are all in
upper case):
BEGIN
WHILE S NEQ NULL OR T NEQ NULL DO
BEGIN
IF S = NULL THEN S := SPACE
ELSE IF T = NULL THEN T := SPACE;
IF S < T THEN RETURN (TRUE);
IF LOP(T) < LOP(S) THEN RETURN (FALSE)
END;
RETURN (TRUE)
END
(4) To remove initial, final, and multiple spaces from a string S :
BEGIN
T := NULL;
WHILE S = SPACE DO C := LOP(S);
WHILE S NEQ NULL DO
IF EQU(S[1 TO 2],"bb") THEN LOP(S)
ELSE T := T & LOP(S);
IF T[INF FOR 1] = SPACE
THEN RETURN (T[1 TO INF - 1])
ELSE RETURN (T)
END
(5) To insert N extra spaces in a string S as uniformly as possible
at the ends of words in order to expand the string. If S ends with
a word, no spaces are inserted after it.
BEGIN
T := NULL;
WHILE N NEQ 0 DO
BEGIN "SHIFTCHAR"
IF S = NULL THEN
BEGIN
S := T;
T := NULL
END;
C := LOP(S);
T := T & C;
IF C NEQ SPACE AND S = SPACE THEN
BEGIN "ADD SPACE"
T := T & SPACE;
N := N-1
END "ADD SPACE"
END "SHIFTCHAR"
END
(6) To remove from S , and return, the longest initial group of words of
not more than 50 characters.
BEGIN
IF LENGTH(S) <= 50 THEN
BEGIN
T := S;
S := NULL;
RETURN (T)
END;
N := 50;
WHILE S[N FOR 1] = SPACE OR S[N+1 FOR 1] NEQ SPACE DO
N := N-1;
T := S[1 TO N];
S := S[N+1 TO INF];
RETURN (T)
END
RANDOM NUMBERS.
SAIL contains a random number generator, which, on successive uses, gives a
series of numbers uniformly distributed between 0 and 1 . While the
numbers are not truly random, they satisfy most statistical tests for
randomness, and can be used to generate dice rolls, coin flips, and other
random events which might be wanted in a computer program.
The random number generator is ordinarily used once with a non-zero integer
argument, called the %seed%, to initialize it; the seed determines which
sequence of numbers it will generate. Thereafter it is used only with a zero
argument, each usage giving a new random number. To use the random number,
evaluate the expression RAN(e) , for any integer expression e ;
X := RAN(314159) initializes the generator with 314159 as the seed, and
also puts a random number into X ; thereafter, X := RAN(0) gives new
random numbers.
From the values of RAN(0) , most of the random numbers we might need can
be obtained. To get a random roll of the dice, we first multiply RAN(0)
by 6 (now it is a random number from 0 to 6 ), add 1 (now it is from
1 to 7 ), and take the integer part by assignment to an integer variable,
thus:
INTEGER DICE
.
.
.
X := RAN(71828)
.
.
.
DICE := 6 * RAN(0) + 1
.
.
.
For a random decimal digit (0 through 9) , it would be
INTEGER DIGIT;
DIGIT := 10 * RAN(0)
For a number uniformly distributed between -3 and 17 ,
REAL X;
X := 20 * RAN(0) - 3
For a number with a triangular distribution, use the smaller of two random
numbers:
X := RAN(0) MIN RAN(0)
or square a random number:
X := RAN(0) ** 2
For a normally distributed number (this distribution is the bell-shaped
curve beloved of statisticians), add twenty four random numbers obtained
from RAN. The resulting number, S , has mean 12 , variance 4 . To get
a number with mean M and variance V , use
(S-12) * .5 + M
Here is how RAN works. It uses one integer variable, which we will call R .
If, in the expression RAN(X) , X is not zero, R is initialized by
assigning X to it. Then R is multiplied by a certain constant, which
we will call K , and the low order 35 (?) bits are taken as the new value
of R . If K has been well chosen, the successive values of R behave
35 -35
like randomly selected integers in (0,2 -1) . Now R * 2 is returned
as the value of RAN(X) ; this number lies in the range 0 <= RAN(X) < 1 .
Example: to generate and print a random hand of 5 cards.
INTEGER SEED, I, CARD
INTEGER ARRAY USED[0:52];
SEED := 0;
WHILE SEED = 0 DO
BEGIN
PRINT ("TYPE IN NON-ZERO SEED FOR RANDOM NUMBER GENERATOR");
SEED := READ
END;
X := RAN(SEED);
FOR I UPTO 52 DO
USED[I-1] := 0;
USED[52] := 1
FOR I UPTO 5 DO
BEGIN
CARD := 52;
WHILE USED[CARD] = 1 DO
CARD := RAN(0) * 52;
USED[CARD] := 1;
PRINT ("A 2 3 4 5 6 7 8 9 10 J Q K "[(CARD REM 13)*2+1 FOR 2],
"OF", "CLUBS DIAMONDS HEARTS SPADES "
[(CARD DIV 4)*8 + 1 FOR 8])
END
The ideas of the above program are: A nonzero seed is obtained from the user.
The array USED keeps track (by 1's) of which cards (code numbers 0 to 51 )
have been used. A card code of 52 is an initialization convention to show
that no card has been picked yet. The first 13 card codes (0 to 12) are
clubs, the next 13 are diamonds, etc; CARD DIV 13 gives the suit number
(0 to 3). Card codes which are multiples of 13 are aces; codes one greater
are 2's, etc. CARD REM 13 gives the rank number (0 to 12).